package com.fyh.ws;

import com.alibaba.fastjson.JSON;
import com.fyh.constant.MessageTypeConstant;
import com.fyh.entity.chat.ChatRecord;
import com.fyh.entity.common.ReceiveMessage;
import com.fyh.entity.common.SendMessage;
import com.fyh.service.ChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
public class ChatWebSocketHandler extends TextWebSocketHandler {

    private static final Map<Long, WebSocketSession> SESSION_MAP = new ConcurrentHashMap<>();

    @Autowired
    private ChatService chatService;

    /**
     * 创建连接成功后调用
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Long userId = (Long) session.getAttributes().get("userId");
        if (userId != null) {
            log.info("user:{}连接成功，Session：{}", userId, session.getId());
            SESSION_MAP.put(userId, session);

            // 获取该用户所有联系人
            List<Long> contactIdList = chatService.getUserContactIdList(userId);
            // 广播（该用户上线）消息给用户所有在线的联系人
            log.info("用户{}上线广播给在线的联系人", userId);
            for (Long contactId : contactIdList) {
                WebSocketSession contactSession = SESSION_MAP.get(contactId);
                if (contactSession != null && contactSession.isOpen()) {
                    try {
                        contactSession.sendMessage(new TextMessage(
                                SendMessage.system(userId, MessageTypeConstant.CHAT, "login", null)));
                        log.info("已通知用户{}本用户上线", contactId);
                    } catch (Exception e) {
                        log.error("发送广播失败：", e);
                    }
                }
            }
        } else {
            log.warn("获取用户id失败，关闭连接");
            session.close();
        }
    }

    /**
     * 接收到消息
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        log.info("收到消息：{}", message.getPayload());
        try {
            ReceiveMessage msg = JSON.parseObject(message.getPayload(), ReceiveMessage.class);
            // 聊天类消息
            if (msg.getType().equals(MessageTypeConstant.CHAT)) {
                sendMessage(msg, session);
            }
            // TODO 其他类型消息
        } catch (Exception e) {
            log.error("处理消息失败", e);
        }
    }

    /**
     * 连接关闭后调用
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Long userId = (Long) session.getAttributes().get("userId");
        if (userId != null) {
            log.info("user:{}断开连接成功", userId);
            SESSION_MAP.remove(userId);

            // 获取该用户所有联系人
            List<Long> contactIdList = chatService.getUserContactIdList(userId);
            // 广播（该用户下线）消息给用户所有在线的联系人
            log.info("用户{}下线广播给在线的联系人", userId);
            for (Long contactId : contactIdList) {
                WebSocketSession contactSession = SESSION_MAP.get(contactId);
                if (contactSession != null && contactSession.isOpen()) {
                    try {
                        contactSession.sendMessage(new TextMessage(
                                SendMessage.system(userId, MessageTypeConstant.CHAT, "logout", null)));
                        log.info("已通知用户{}本用户下线", contactId);
                    } catch (Exception e) {
                        log.error("发送广播失败：", e);
                    }
                }
            }
        } else {
            log.warn("获取用户id失败");
        }
    }

    /**
     * 发送消息给目标联系人
     * @param msg
     * @param session
     */
    private void sendMessage(ReceiveMessage msg, WebSocketSession session) {
        try {
            Long userId = (Long) session.getAttributes().get("userId");
            Long contactId = msg.getAimId();
            log.info("目标联系人id：{}", contactId);
            WebSocketSession targetSession = SESSION_MAP.get(contactId);

            String mess = msg.getMessage();
            log.info("消息：{}", mess);
            List<String> filePathList = msg.getFilePathList();

            if (targetSession != null && targetSession.isOpen()) {
                targetSession.sendMessage(new TextMessage(SendMessage.user(userId, MessageTypeConstant.CHAT, mess, filePathList)));
                log.info("已发送消息给用户{}", contactId);
            }

            // 保存聊天记录
            ChatRecord chatRecord = new ChatRecord();
            chatRecord.setSenderId(userId);
            chatRecord.setReceiverId(contactId);
            chatRecord.setMessage(mess);
            chatRecord.setSendTime(LocalDateTime.now());

            chatService.insertChatRecord(chatRecord);
        } catch (IOException e) {
            log.error("发送消息失败：", e);
        }
    }

    /**
     * 发送投递成功消息给HR
     * @param positionId
     * @param employerId
     */
    public void sendDeliveryMessage(Long positionId, Long employerId) {
        try {
            WebSocketSession session = SESSION_MAP.get(employerId);
            if (session != null && session.isOpen()) {
                session.sendMessage(new TextMessage(
                        SendMessage.system(positionId, MessageTypeConstant.DELIVERY, null, null)));
            }
        } catch (IOException e) {
            log.error("发送消息失败：", e);
        }
    }

    /**
     * 发送通知给用户
     * @param receiverId
     */
    public void sendInform(Long receiverId) {
        try {
            WebSocketSession session = SESSION_MAP.get(receiverId);
            if (session != null && session.isOpen()) {
                session.sendMessage(new TextMessage(
                        SendMessage.system(null, MessageTypeConstant.INFORM, null, null)));
            }
        } catch (IOException e) {
            log.error("发送通知失败：", e);
        }
    }
}
